<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
<script>

    let data={
        list:[{
            a:1
        },{
            a:2
        }]
    }

    class Observer{
        constructor(data){
            this.observer(data) ;
        }
        observer(data){
            if(data&&typeof data === 'object'){
                this.defineProps('__ob__',this,data)
                if(Array.isArray(data)){
                    this.defineArray(data);
                }
                else {
                    this.defineObject(data);
                }
            }
        }
        //处理对象
        defineObject(data){
            Object.keys(data).forEach(key=>{
                 this.defineReactive(key,data[key],data)
            })
        }
        //处理数组
        defineArray(data){
            data.__proto__ = this.changeArrayMethods()
            data.forEach(item=>{
                this.observer(item);
            })
        }
        defineProps(key,value,obj){
            Object.defineProperty(obj,key,{
                value,
                enumerable:false
            })
        }
        //数据劫持
        defineReactive(key,value,obj){
            this.observer(value); // 递归查询下面的数据
             Object.defineProperty(obj,key,{
                 enumerable:true,
                 configurable:true,
                 get(){
                     return value
                 },
                 set(newVal){
                     value = newVal
                 }
             })
        }
        changeArrayMethods(){
            const oldMethodArray = Array.prototype;   // 数组的原型链
            const newMethodArray = Object.create(oldMethodArray); // 将newMethodArray的原型链指向oldMethodArray
            const methods = ['push','pop','shift','unshift','reverse','sort','splice']   //需要重写的方法

            //遍历重写
            methods.forEach(item=>{
                newMethodArray[item] = function(...args){
                    console.log("调用了方法"+item);
                   let result = oldMethodArray[item].apply(this,args);  // 重新调用数组的方法
                    let addNumber;
                    switch (item) {
                        case 'push':
                        case 'unshift':
                           addNumber = args
                            break;
                        case 'splice':
                           addNumber=args.slice(2)
                            break;
                    }
                    if(addNumber){
                        // console.log(this,'++++');
                        this.__ob__.defineArray(addNumber);
                    }
                    return result;
                }
            })
            return newMethodArray;
        }
    }

    //数组方法重写


    new Observer(data)
    console.log(data)
</script>
</html>